package com.hulytu.android.compat;

import static android.content.pm.PackageManager.PERMISSION_GRANTED;

import android.Manifest;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.MediaStore;
import android.support.v4.content.FileProvider;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.File;
import java.io.IOException;
import java.util.Objects;

public class PhotosCompat {

    private static final int REQUEST_CODE_PERMISSIONS = 0x1001;

    public static final int REQUEST_CODE_TAKE_PICTURE = 0x2001;

    public static final int REQUEST_CODE_ALBUM = 0x2002;

    public static final int REQUEST_CODE_CROP = 0x2003;

    /**
     * 无权限
     */
    public static final int FAILED_NO_PERMISSION = 0x700;

    /**
     * 创建临时文件失败
     */
    public static final int FAILED_CREATE_TEMP_FILE = 0x701;

    private static final boolean isQ = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q;

    @NotNull
    private final Activity activity;

    private final String fileProviderAuthority;

    private Photo photo;
    private Photo cropPhoto;

    private OnPhotoResultCallback callback;

    private int requestCode;

    public PhotosCompat(@NotNull Activity activity, @NotNull String fileProviderAuthority) {
        this.activity = activity;
        this.fileProviderAuthority = fileProviderAuthority;
    }

    /**
     * 拍照
     *
     * @param callback
     */
    public void takePicture(OnPhotoResultCallback callback) {
        requestCode = REQUEST_CODE_TAKE_PICTURE;
        this.callback = Objects.requireNonNull(callback);

        if (hasPermissions(new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE})) {
            toAndroidCamera();
        }
    }

    /**
     * 相册选择
     *
     * @param callback
     */
    public void album(OnPhotoResultCallback callback) {
        requestCode = REQUEST_CODE_ALBUM;
        this.callback = Objects.requireNonNull(callback);

        if (hasPermissions(
                new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE})
        ) {
            album();
        }
    }


    private void toAndroidCamera() {
        photo = new Photo("IMG_" + System.currentTimeMillis() + ".png");

        Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

        makeImageUri(photo);

        //对目标应用临时授权该Uri所代表的文件
        cameraIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        //对目标应用临时授权该Uri所代表的文件
        cameraIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
        // 将拍取的照片保存到指定URI
        cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, photo.uri);

        activity.startActivityForResult(cameraIntent, REQUEST_CODE_TAKE_PICTURE);
    }

    private void makeImageUri(Photo photo) {
        if (isQ) {
            photo.uri = createImageUri(photo.name);
        } else {
            File file = createCameraTempImageFile(photo.name);

            if (file == null) {
                callback.onTakeFailed(REQUEST_CODE_TAKE_PICTURE, FAILED_CREATE_TEMP_FILE);
                return;
            }

            photo.uri = getUri(file);
            photo.file = file;
        }
    }

    /**
     * 创建图片地址uri,用于保存拍照后的照片 Android 10以后使用这种方法
     */
    private Uri createImageUri(String name) {
        //设置保存参数到ContentValues中
        ContentValues contentValues = new ContentValues();
        //设置文件名
        contentValues.put(MediaStore.Images.Media.DISPLAY_NAME, name);
        //兼容Android Q和以下版本
        if (isQ) {
            //android Q中不再使用DATA字段，而用RELATIVE_PATH代替
            //RELATIVE_PATH是相对路径不是绝对路径;照片存储的地方为：存储/Pictures
            contentValues.put(MediaStore.Images.Media.RELATIVE_PATH, "Pictures");
        }
        //设置文件类型
        contentValues.put(MediaStore.Images.Media.MIME_TYPE, "image/png");
        //执行insert操作，向系统文件夹中添加文件
        //EXTERNAL_CONTENT_URI代表外部存储器，该值不变
        return activity.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                contentValues);
    }

    private File createCameraTempImageFile(String name) {
        File dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);

        File file = new File(dir, name);
        try {
            if (file.createNewFile()) {
                return file;
            }

            return null;
        } catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }


    private Uri getUri(File file) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            return FileProvider.getUriForFile(activity, fileProviderAuthority, file);
        } else {
            return Uri.fromFile(file);
        }
    }

    private void album() {
        Intent intent = new Intent(Intent.ACTION_PICK);
        intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
        activity.startActivityForResult(intent, REQUEST_CODE_ALBUM);
    }

    public boolean onActivityResult(int requestCode, int resultCode, Intent data) {

        Uri uri;
        switch (requestCode) {
            case REQUEST_CODE_TAKE_PICTURE:
                uri = resultCode == Activity.RESULT_OK ? photo.uri : null;
                cropImage(requestCode, uri, uri == null ? null : photo.getCropDataUri(activity));
                return true;

            case REQUEST_CODE_ALBUM:
                uri = resultCode == Activity.RESULT_OK && data != null ? data.getData() : null;
                cropImage(requestCode, uri, uri);
                return true;

            case REQUEST_CODE_CROP:
                uri = resultCode == Activity.RESULT_OK ? cropPhoto.uri : null;
                callback.onCropResult(uri);
                return true;

            default:
                break;
        }

        return false;
    }

    private void cropImage(int requestCode, Uri uri, Uri cropDataUri) {
        cropPhoto = new Photo("Crop_Image_" + System.currentTimeMillis() + ".png");
        makeImageUri(cropPhoto);

        Intent intent = callback.onTakeResult(requestCode, uri, createIntentCrop(cropDataUri, cropPhoto.getCropUri()));

        if (intent != null && cropDataUri != null) {
            activity.startActivityForResult(intent, REQUEST_CODE_CROP);
        }
    }

    public boolean onRequestPermissionsResult(int requestCode, @NotNull final String[] permissions, @NotNull int[] grantResults) {

        if (requestCode == REQUEST_CODE_PERMISSIONS) {
            for (int result : grantResults) {
                if (result != PERMISSION_GRANTED) {
                    callback.onTakeFailed(requestCode, FAILED_NO_PERMISSION);
                    return true;
                }
            }

            switch (this.requestCode) {
                case REQUEST_CODE_TAKE_PICTURE:
                    toAndroidCamera();
                    break;
                case REQUEST_CODE_ALBUM:
                    album();
                    break;
                default:

                    break;

            }


            return true;
        }

        return false;
    }

    protected Intent createIntentCrop(Uri uri, Uri cropUri) {
        Intent intent = new Intent("com.android.camera.action.CROP");
        intent.setDataAndType(uri, "image/*");
        intent.putExtra("crop", "true");
        intent.putExtra("return-mData", false);
        intent.putExtra(MediaStore.EXTRA_OUTPUT, cropUri);
        intent.putExtra("outputFormat", Bitmap.CompressFormat.PNG.toString());
        intent.putExtra("noFaceDetection", true);
        return intent;
    }


    private boolean hasPermissions(String[] permissions) {
        // 权限处理
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {

            PackageManager manager = activity.getPackageManager();
            String packageName = activity.getPackageName();

            for (String permission : permissions) {
                if (manager.checkPermission(permission, packageName) != PERMISSION_GRANTED) {
                    activity.requestPermissions(permissions, REQUEST_CODE_PERMISSIONS);
                    return false;
                }
            }
        }

        return true;
    }

    public interface OnPhotoResultCallback {

        void onTakeFailed(int requestCode, int type);

        /**
         * @param requestCode {@link #REQUEST_CODE_TAKE_PICTURE} 拍照
         *                    {@link #REQUEST_CODE_ALBUM} 相册
         * @param uri         如果为 null 代表用户取消了
         * @param cropIntent  裁剪的 intent
         * @return 如果需要裁剪，返回裁剪的相关参数，不需要则返回 null
         */
        @Nullable
        Intent onTakeResult(int requestCode, Uri uri, @NotNull Intent cropIntent);

        /**
         * @param uri 裁剪后的 uri
         */
        void onCropResult(Uri uri);
    }

    private static class Photo {
        String name;

        Uri uri;

        /**
         * 低于 android 10 使用
         */
        File file;

        public Photo(String name) {
            this.name = name;
        }

        Uri getCropDataUri(Context context) {
            return isQ ? uri : getCropDataUriLowQ(context);
        }

        Uri getCropUri() {
            return file == null ? uri : Uri.fromFile(file);
        }

        private Uri getCropDataUriLowQ(Context context) {
            File file = this.file;

            if (file == null) return null;


            ContentResolver resolver = context.getContentResolver();

            try (Cursor cursor = resolver
                    .query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                            new String[]{MediaStore.Images.Media._ID},
                            MediaStore.Images.Media.DATA + "=?",
                            new String[]{file.getAbsolutePath()},
                            null
                    );) {

                Uri uri;
                int idColumnIndex;
                if (cursor == null || !cursor.moveToFirst()) {
                    uri = null;

                } else if ((idColumnIndex = cursor.getColumnIndex(MediaStore.Images.ImageColumns._ID)) > 0) {
                    int index = cursor.getInt(idColumnIndex);
                    uri = Uri.parse("content://media/external/images/media/" + index);

                } else {
                    uri = null;
                }

                if (uri != null) return uri;

                if (file.exists()) {
                    ContentValues values = new ContentValues();
                    values.put(MediaStore.Images.Media.DATA, file.getAbsolutePath());
                    return resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
                }

                return null;

            }
        }
    }
}
